#include "Col.ph"
#ifdef __GNUG__
#pragma implementation
#endif

#include "Symbol.h"

#include "Class.h"
#include "String.h"
#include "Math.h"
#include "ET_stdio.h"

//---- SymbolTable -------------------------------------------------------------

NewMetaImpl(SymbolTable,Object, (T(size), TVP(table,capacity)));

SymbolTable::SymbolTable(int cap)
{
	if (cap < 200)
		cap= 200;
	capacity= Math::NextPrime(cap);
	table= new char* [capacity];
	size= 0;
}

SymbolTable::~SymbolTable()
{
	if (table) {
		register int i;
		for (i= 0; i < capacity; i++)
			SafeDelete(table[i]);
		SafeDelete(table);
	}
}

int SymbolTable::GetSlot(const char *s)
{
	register u_long slot, n;
	register char *slotOp;
	
	slot= strhash(s) % capacity;
	for (n= 0; n < capacity; n++) {
		if ((slotOp= table[slot]) == 0)
			break;
		if (strcmp(s, slotOp) == 0)
			break;
		if (++slot == capacity)
			slot= 0;
	}
	return slot;
}

void SymbolTable::Expand()
{
	register int i;
	register char **oldTable= table, *s;
	int oldcapacity= capacity;

	capacity= Math::NextPrime(2*oldcapacity);
	table= new char* [capacity];
	size= 0;
	for (i= 0; i < oldcapacity; i++)
		if (s= oldTable[i]) {
			table[GetSlot(s)]= s;
			size++;
		}
	delete oldTable;
}

const char *SymbolTable::MakeId(const char *s)
{
	if (s == 0)
		return 0;

	register const char **ss= &table[GetSlot(s)];
	if (*ss)
		return *ss;
	const char *sss= strsave(s);
	*ss= sss;
	if (++size >= ((3*capacity)/4))
		Expand();
	return sss;
}

//---- Symbol -----------------------------------------------------------------

SymbolTable *Symbol::SymTab= 0;

ONEXIT(Symbol)
{
	SafeDelete(Symbol::SymTab);
}

const char *Symbol::MakeId(const char *s)
{
	if (SymTab == 0)
		SymTab= new SymbolTable;
	return SymTab->MakeId(s);
}

OStream &Symbol::PrintOn(OStream &os) const
{
	return os.PrintString(id);
}

IStream &Symbol::ReadFrom(IStream &is)
{
	char *tmp= 0;

	is.ReadString(&tmp);
	id= MakeId(tmp);
	SafeDelete(tmp);
	return is;
}

SimpleMetaImpl(Symbol)
{
	len= len;
	if (! isptr)
		sprintf(buf, "%s", ((Symbol*)addr)->AsString());
}

